Spring Data JPA相关接口介绍及简单应用

Repository接口及其子接口介绍

Repository接口

接口定义:

1
2
public interface Repository<T, ID extends Serializable> {
}

Repository接口是一个空接口,这个接口主要作为一个标记接口来捕获类型的工作,并帮助你发现继承这个接口的接口。

CrudRepository接口

CrudRepository接口继承Repository接口,实现了CRUD相关方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S var1);

T findOne(ID var1);

boolean exists(ID var1);

Iterable<T> findAll();

long count();

void delete(T entity);

// … more functionality omitted.
}

PagingAndSortingRepository接口

PagingAndSortingRepository接口继承CrudRepository接口,实现了分页排序相关的方法:

1
2
3
4
5
6
7
public interface PagingAndSortingRepository<T, ID extends Serializable> 
extends CrudRepository<T, ID> {

Iterable<T> findAll(Sort var1);

Page<T> findAll(Pageable var1);
}

JpaRepository接口

JpaRepository接口继承PagingAndSortingRepository接口,实现了JPA规范的相关方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface JpaRepository<T, ID extends Serializable> 
extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

List<T> findAll(Sort var1);

<S extends T> List<S> save(Iterable<S> var1);

void flush();

<S extends T> S saveAndFlush(S var1);

void deleteInBatch(Iterable<T> var1);

// … more functionality omitted.
}

使用方法命名规则查询

Spring Data JPA支持以特定的方法命名规则来生成查询。

下面是对JPA支持的关键字的概述,以及包含该关键字翻译成的sql片段。

KeywordSampleJPQL snippet
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1
ContainingfindByFirstnameContaining… where x.firstname like ?1
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection<Age> ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection<Age> ages)… where x.age not in ?1
TruefindByActiveTrue()… where x.active = true
FalsefindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

In和NotIn可以将Collection的任何子类作为参数以及数组或可变参数。

例子:

1
2
3
4
5
6
7
8
public interface UserRepository extends Repository<User, Long> {

List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
// where name like ?% and age <?
List<User> findByNameStartingWithAndAgeLessThan(String name, Integer age);
// where name in (?,?....) or age <?
List<User> findByNameInOrAgeLessThan(List<String> names, Integer age);
}

使用按照方法命名规则,有弊端:

  • 方法名会比较长: 约定大于配置
  • 对于一些复杂的查询,是很难实现

使用@Query注解

对查询方法进行注释的查询优先于使用@NamedQuery定义的查询或者在orm.xml中声明的命名查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface UserRepository extends JpaRepository<User, Long> {

//占位符的方式
@Query("select u from User u where u.firstname = ?1 or u.lastname = ?2")
User findByLastnameOrFirstname(String lastname, String firstname);

//命名参数的方式
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);

//使用@Query手动定义查询,允许在查询定义内定义高级LIKE表达式。
@Query("select u from User u where u.firstname like %?1")
List<User> findByFirstnameEndsWith(String firstname);
}

@Query注释允许通过将nativeQuery设置为true来执行原生sql查询。

1
2
3
4
5
public interface UserRepository extends JpaRepository<User, Long> {

@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}

@Query、@Modifying、@Transactional综合使用

使用@Query执行更新操作需要配合@Modifying注解和@Transactional注解。

事务一般在service层控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface UserRepository extends Repository<User, Long> {

@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);

@Modifying
@Query("delete from User u where user.role.id = ?1")
void deleteInBulkByRoleId(long roleId);
}

public class UserService {

@Autowired
private UserRepository userRepository;

@Transactional
public int setAge(Integer age, Integer id){
return userRepository.setFixedFirstnameFor(age, id);
}
}

参考链接

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference